package legumes.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.Maps;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.event.MarkerDragEndHandler;
import com.google.gwt.maps.client.event.MarkerDragStartHandler;
import com.google.gwt.maps.client.geocode.DirectionQueryOptions;
import com.google.gwt.maps.client.geocode.DirectionResults;
import com.google.gwt.maps.client.geocode.Directions;
import com.google.gwt.maps.client.geocode.DirectionsCallback;
import com.google.gwt.maps.client.geocode.StatusCodes;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.maps.client.overlay.Polygon;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.TextArea;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class TestsSMA implements EntryPoint {

	// GWT module entry point method.
	public void onModuleLoad() {
		/*
		 * Asynchronously loads the Maps API.
		 * 
		 * The first parameter should be a valid Maps API Key to deploy this
		 * application on a public server, but a blank key will work for an
		 * application served from localhost.
		 */
		Maps.loadMapsApi("", "2", false, new Runnable() {
			public void run() {
				buildUi();
			}
		});
	}
	private TextArea ta;
	private void buildUi() {
		// Open a map centered on Cawker City, KS USA
		final LatLng tlseCity = LatLng.newInstance(43.624, 1.414);

		final MapWidget map = new MapWidget(tlseCity, 2);
		map.setSize("100%", "100%");
		// Add some controls for the zoom level
		map.addControl(new LargeMapControl());

		// Add a marker
		MarkerOptions mo = MarkerOptions.newInstance();
		mo.setDraggable(true);
		final Marker marker = new Marker(tlseCity, mo);
		marker.addMarkerDragEndHandler(new MarkerDragEndHandler(){

			@Override
			public void onDragEnd(MarkerDragEndEvent event) {
				drawCircle(map, marker.getLatLng(), Integer.parseInt(ta.getValue()));
			}
			
		});
		map.addOverlay(marker);

		// Add an info window to highlight a point of interest
		map.getInfoWindow().open(map.getCenter(),
				new InfoWindowContent("World's Largest Ball of Sisal Twine"));

		final DockLayoutPanel dock = new DockLayoutPanel(Unit.PX);
		dock.addNorth(map, 500);
		ta = new TextArea();
		ta.addValueChangeHandler(new ValueChangeHandler<String>() {

			@Override
			public void onValueChange(ValueChangeEvent<String> event) {
				drawCircle(map, marker.getLatLng(), Integer.parseInt(ta.getValue()));
			}
		});
		ta.setValue("60");
		dock.addSouth(ta, 100);
		// Add the map to the HTML host page
		RootLayoutPanel.get().add(dock);

		DirectionQueryOptions opts = new DirectionQueryOptions(map);
		String query = "from: Toulouse, France  to: Albi, France";
		Directions.load(query, opts, new DirectionsCallback() {

			public void onFailure(int statusCode) {
				Window.alert("Failed to load directions: Status "
						+ StatusCodes.getName(statusCode) + " " + statusCode);
			}

			public void onSuccess(DirectionResults result) {
				GWT.log("Successfully loaded directions : distance="
						+ result.getDistance().inMeters());

			}
		});

		drawCircle(map, LatLng.newInstance(43.57545, 1.46717), 60);
	}

	private Polygon circleLine;
	private LatLng circleResizerOriginLatLng = null;
	private Marker markerCircleResizer;
	
	private void drawCircle(final MapWidget map, final LatLng center, final int radius) {
		if (circleLine != null) {
			map.removeOverlay(circleLine);
		}
		if( markerCircleResizer != null ){
			map.removeOverlay(markerCircleResizer);
		}
		
		final LatLngBounds bounds = LatLngBounds.newInstance();
		List<LatLng> circlePoints = new ArrayList<LatLng>();
		int circleRadius = (radius);// /1000); //km
		double d = circleRadius / 6378.8; // radians : Earth radius = 6378.8km
		double lat1 = center.getLatitudeRadians();// (Math.PI / 180) * center.getLatitude(); // radians
		double lng1 = center.getLongitudeRadians(); //(Math.PI / 180) * center.getLongitude(); // radians
		for (double a = 0; a < 361; a++) {
			double tc = (Math.PI / 180) * a;
			double y = Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1)
					* Math.sin(d) * Math.cos(tc));
			double dlng = Math.atan2(
					Math.sin(tc) * Math.sin(d) * Math.cos(lat1), Math.cos(d)
							- Math.sin(lat1) * Math.sin(y));
			double x = ((lng1 - dlng + Math.PI) % (2 * Math.PI)) - Math.PI; // MOD
																			// function
			LatLng point = LatLng.newInstance(y * (180 / Math.PI), x
					* (180 / Math.PI));
			circlePoints.add(point);
			bounds.extend(point);
		}
		MarkerOptions mo = MarkerOptions.newInstance();
		mo.setDraggable(true);
		LatLng quartPoint = LatLng.newInstance(center.getLatitude(), circlePoints.get( ((int)Math.floor(circlePoints.size()/4))*3 ).getLongitude());
		markerCircleResizer = new Marker(quartPoint, mo);
		markerCircleResizer.addMarkerDragStartHandler(new MarkerDragStartHandler(){

			@Override
			public void onDragStart(MarkerDragStartEvent event) {
				circleResizerOriginLatLng = markerCircleResizer.getLatLng();
			}
			
		});
		markerCircleResizer.addMarkerDragEndHandler(new MarkerDragEndHandler(){

			@Override
			public void onDragEnd(MarkerDragEndEvent event) {
				LatLng senderLatLng = event.getSender().getLatLng();
				double radiusDelta = computeDistance(center, senderLatLng);
				GWT.log("Radius= " + radiusDelta + " km");
				drawCircle(map, center, (int)radiusDelta);
			}
			
		});
		
		map.addOverlay(markerCircleResizer);
		
		
		String color = "#0a00a5";
//		if (d < 1.5678565720686044) {
//			circleLine = new Polygon(circlePoints.toArray(new LatLng[0]),
//					color, 2, 1, color, 0.25);
//		} else {
			circleLine = new Polygon(circlePoints.toArray(new LatLng[0]),
					color, 2, 1, color, 0.25);
//		}
		map.addOverlay(circleLine);
		
		Timer t = new Timer() {
		      public void run() {
		    	  map.setZoomLevel(map.getBoundsZoomLevel(bounds));
					map.setCenter(center);
		      }
		    };

		    // Schedule the timer to run once in 5 seconds.
		    t.schedule(400);
		    Marker mcenter = new Marker(center);
			map.addOverlay(mcenter);
			
	}
	
	private double computeDistance(LatLng source_, LatLng dest_){
		return Math.acos(Math.sin(source_.getLatitudeRadians())*
				Math.sin(dest_.getLatitudeRadians())+
				Math.cos(source_.getLatitudeRadians())*Math.cos(dest_.getLatitudeRadians())*
				Math.cos(dest_.getLongitudeRadians()-source_.getLongitudeRadians()) )*6371;
	}
}
